package com.swm.julie.rest.sausage.search;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Formatter;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.swm.julie.rest.sausage.index.field.Product;

public class SausageSearcherImpl implements SausageSearcher {

	private Logger logger = LoggerFactory.getLogger(SausageSearcherImpl.class);
	String indexDir = "/index";

	@Override
	public Object[] standardSearch(String query) throws IOException, ParseException {
		//		System.out.println("SausageSearcherImpl.standardSearch()");

		if(query == null) 
		{
			logger.error("null query");
			return null;
		}

		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		QueryParser parser;
		Analyzer cjkAnalyzer = new CJKAnalyzer(Version.LUCENE_34);
		Analyzer stdAnalyzer = new StandardAnalyzer(Version.LUCENE_34);

		Document fieldGetter = searcher.doc(0);

		for(Fieldable fieldable : fieldGetter.getFields())
		{
			Field field = (Field) fieldable;
			
			BooleanQuery bq = new BooleanQuery();
			
			parser = new QueryParser(Version.LUCENE_34, field.name(), stdAnalyzer);
			Query q = parser.parse(query);
			bq.add(q, Occur.MUST);
			
			parser = new QueryParser(Version.LUCENE_34, field.name(), cjkAnalyzer);
			q = parser.parse(query);
			bq.add(q, Occur.MUST);
			

			TopDocs docs = searcher.search(bq, 500);
			if(docs.totalHits > 0)
			{
				for(ScoreDoc doc : docs.scoreDocs)
				{
					Document document = searcher.doc(doc.doc);

					//					System.out.println("search " + document.get(field.name()));
					Product product = getProduct(document);

//					if(isExist(res, product)) continue;
//					else res.add(product);
					res.add(product);
				}
			}

		}
		
		searcher.close();
		dir.close();

		logger.info(new Formatter().format("standardSearch : %s query, hits %d",  query, res.size()).toString());
		
		return res.toArray();
	}


	@Override
	public Object[] companySearch(String query) throws IOException, ParseException {

		//		System.out.println("SausageSearcherImpl.companySearch()");
		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		//prepare the query based on itemName field with CJKAnalyzer
//		QueryParser parser = new QueryParser(Version.LUCENE_34, "company", new CJKAnalyzer(Version.LUCENE_34));
//		Query q = parser.parse(query);
		TermQuery q = new TermQuery(new Term("company", query));

		//long start = System.currentTimeMillis();
		TopDocs hits = searcher.search(q, 500);
		//long end = System.currentTimeMillis();

		for(ScoreDoc doc : hits.scoreDocs)
		{
			Document document = searcher.doc(doc.doc);

			//			System.out.println("search " + document.get("company"));
			Product product = getProduct(document);

			res.add(product);
		}

		searcher.close();
		dir.close();
		
		logger.info(new Formatter().format("companySearch : %s company, hits %d",  query, res.size()).toString());

		return res.toArray();
	}


	@Override
	public Object[] itemCompanySearch(String company, String query) throws IOException, ParseException {
		//		System.out.println("SausageSearcherImpl.itemCompanySearch()");
		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		//prepare the query based on itemName field with each Analyzer
		BooleanQuery bq = new BooleanQuery(true);
		TermQuery companyQ = new TermQuery(new Term("company", company));
		bq.add(companyQ, Occur.MUST);
		
		QueryParser parser = new QueryParser(Version.LUCENE_34, "itemName", new CJKAnalyzer(Version.LUCENE_34));
		Query q = parser.parse(query);
		bq.add(q, Occur.MUST);
		
		parser = new QueryParser(Version.LUCENE_34, "itemName", new StandardAnalyzer(Version.LUCENE_34));
		q = parser.parse(query);
		bq.add(q, Occur.MUST);

		TopDocs hits = searcher.search(bq, 500);

		for(ScoreDoc doc : hits.scoreDocs)
		{
			Document document = searcher.doc(doc.doc);

			//			System.out.println("search " + document.get("company"));
			Product product = getProduct(document);

			res.add(product);
		}

		searcher.close();
		dir.close();
		
		logger.info(new Formatter().format("itemCompanySearch : %s company, %s query, hits %d",  company, query, res.size()).toString());

		return res.toArray();
	}


	@Override
	public Object[] provinceSearch(String query) throws IOException, ParseException {
		//		System.out.println("SausageSearcherImpl.provinceSearch()");
		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		//prepare the query based on itemName field with CJKAnalyzer
//		QueryParser parser = new QueryParser(Version.LUCENE_34, "locate", new CJKAnalyzer(Version.LUCENE_34));
//		Query q = parser.parse(query);
		TermQuery q = new TermQuery(new Term("locate", query));

		TopDocs hits = searcher.search(q, 500);

		for(ScoreDoc doc : hits.scoreDocs)
		{
			Document document = searcher.doc(doc.doc);

			Product product = getProduct(document);

			res.add(product);
		}

		searcher.close();
		dir.close();

		logger.info(new Formatter().format("provinceSearch : %s province, hits %d",  query, res.size()).toString());		
		
		
		return res.toArray();
	}
	
	@Override
	public Object[] itemProvinceSearch(String province, String query)
			throws IOException, ParseException {
		// TODO Auto-generated method stub
		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		//prepare the query based on itemName field with each Analyzer
		BooleanQuery bq = new BooleanQuery();
		
		TermQuery provinceQ = new TermQuery(new Term("locate", province));
		bq.add(provinceQ, Occur.MUST);

		QueryParser parser = new QueryParser(Version.LUCENE_33, "itemName", new CJKAnalyzer(Version.LUCENE_33));
		Query q = parser.parse(query);
		bq.add(q, Occur.MUST);
		
		parser = new QueryParser(Version.LUCENE_34, "itemName", new StandardAnalyzer(Version.LUCENE_34));
		q = parser.parse(query);
		bq.add(q, Occur.MUST);
		
		TopDocs hits = searcher.search(bq, 500);

		for(ScoreDoc doc : hits.scoreDocs)
		{
			Document document = searcher.doc(doc.doc);

			//			System.out.println("search " + document.get("company"));
			Product product = getProduct(document);

			res.add(product);
		}
		
		searcher.close();
		dir.close();
		
		logger.info(new Formatter().format("itemProvinceSearch : %s province, %s query, hits %d",  province, query, res.size()).toString());
		
		return res.toArray();
	}

	/**
	 * Return search result, product list, with item name query
	 * @param itemq
	 * @return 
	 * @throws IOException 
	 * @throws ParseException 
	 */
	public Object[] itemSearch(String item, String query) throws IOException, ParseException
	{
		//		System.out.println("SausageSearcher.itemSearch()");
		ArrayList<Product> res = new ArrayList<Product>();

		//open the index directory
		Directory dir = FSDirectory.open(new File(indexDir));
		IndexSearcher searcher = new IndexSearcher(dir, true);

		//prepare the query based on itemName field with CJKAnalyzer
		BooleanQuery bq = new BooleanQuery(true);
		
		TermQuery itemQ = new TermQuery(new Term("item", item));
		bq.add(itemQ, Occur.MUST);
		
		QueryParser parser = new QueryParser(Version.LUCENE_34, "itemName", new CJKAnalyzer(Version.LUCENE_34));
		Query q = parser.parse(query);
		bq.add(q, Occur.MUST);
		
		parser = new QueryParser(Version.LUCENE_34, "itemName", new StandardAnalyzer(Version.LUCENE_34));
		q = parser.parse(query);
		bq.add(q, Occur.MUST);
		
		//long start = System.currentTimeMillis();
		TopDocs hits = searcher.search(bq, 500);
		//long end = System.currentTimeMillis();

		for(ScoreDoc doc : hits.scoreDocs)
		{
			Document document = searcher.doc(doc.doc);

			//			System.out.println("search " + document.get("itemName"));
			Product product = getProduct(document);

			res.add(product);
		}

		searcher.close();
		dir.close();
		

		logger.info(new Formatter().format("itemSearch : %s item, %s query, hits %d",  item, query, res.size()).toString());

		return res.toArray();
	}

	//annotation으로 처리하고 싶음..
	/**
	 * convert document info to product instance
	 * @param doc
	 * @return
	 */
	private Product getProduct(Document doc)
	{
		Product product = new Product();
		product.setCompany(doc.get("company"));
		product.setItemName(doc.get("itemName"));
		product.setImage(doc.get("image"));
		product.setUrl(doc.get("url"));
		product.setItem(doc.get("item"));
		product.setLocate(doc.get("locate"));
		product.setDiscountRatio(Double.valueOf(doc.get("discountRatio")));
		product.setPrice(doc.get("price"));
		product.setShopName(doc.get("shopName"));
		product.setShopPhone(doc.get("shopPhoe"));
		product.setShopLocate(doc.get("shopLocate"));
		product.setBuyStart(doc.get("buyStart"));
		product.setBuyEnd(doc.get("buyEnd"));
		product.setUseStart(doc.get("useStart"));
		product.setUseEnd(doc.get("useEnd"));

		return product;
	}

//	private boolean isExist(ArrayList<Product> list, Product product)
//	{
//		for(Product test : list)
//		{
//			if(test.company.equals(instance.getCompany())
//					|| test.itemName.equals(instance.getItemName())
//					|| test.image.equals(instance.getImage())
//					|| test.url.equals(instance.getUrl())
//					|| test.item.equals(instance.getItem())
//					|| test.locate.equals(instance.getLocate())
//					|| test.discountRatio == instance.getDiscountRatio()
//					|| test.price.equals(instance.getPrice())
//					|| test.shopName.equals(instance.getShopName())
//					|| test.shopPhone.equals(instance.getShopPhone())
//					|| test.shopLocate.equals(instance.getShopLocate())
//					|| test.buyStart.equals(instance.getBuyStart())
//					|| test.buyEnd.equals(instance.getBuyEnd())
//					|| test.useStart.equals(instance.getUseStart())
//					|| test.useEnd.equals(instance.getUseEnd()))
//				{
//					return true;
//				}else return false;
//		}
//		
//		return false;
//	}
//	private String getProvince(String provinceF)
//	{

	//		/**
//		 * seoul,//서울
//	gangnam, //반포, 강남, 역삼, 선릉, 양재, 삼성
//	apguj, //압구정, 신사, 청담
//	seocho, // 논현
//	jamsil, // 송파, 잠실
//	gangdong, //강동, 노원, 동대문
//	yngdngpo, // 영등포, 금천, 구로, 강서
//	md, // 명동, 을지로, 
//	etw, // 이태원
//	jongno, //종로
//	sinchon, // 신촌, 이대
//	hong,  // 홍대
//	ggi, // 경기도
//	etc, // 그 외 지역들
//	deault; // 상관 없음
//		 */
//		switch (ShopProvince.valueOf(provinceF))
//		{
//		case seoul : return "서울";
//		case gangnam : return "반포 강남 역삼 선릉 양재 삼성";
//		case apguj : return "압구정 신사 청담"; 
//		case seocho : return "논현";
//		case jamsil : return "송파 잠실";
//		case gangdong : return "강동 노원 동대문";
//		case yngdngpo : return "영등포 금천 구로 강서";
//		case md : return "명동";
//		case etw : return "이태원";
//		case jongno : return "종로";
//		case sinchon : "신";
//		case hong : break;
//		case ggi : break;
//		case etc : break;
//		case deault : break;
//		}
//	}

}
